﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SmartProject.Entity;
using SmartProject.Exceptions;

using NHibernate;

namespace SmartProject.BusinessRules
{
    public class FirstInitialAndLastNameUsername : BusinessRule
    {
        public override string Name
        {
            get { return "First initial, last name username"; }
        }

        public override string Description
        {
            get
            {
                return "Username is first initial of first name and concatenated last names";
            }
        }

        /// <summary>
        /// Returns true if the first name or last name has changed.
        /// </summary>
        /// <param name="session"></param>
        /// <param name="user">Current user instance that may have changed.</param>
        /// <returns>True if the first name AND/OR last name has changed.</returns>
        private bool IsChanged(ISession session, User user)
        {
            string previousFirstNameInitial;
            string previousLastName;
            using (var newSession = SmartProject.Data.DataProvider.Instance.Session)
            {
                User previous = User.GetUser(newSession, user.Id);

                previousFirstNameInitial = previous.FirstName.Substring(0, 1).ToLower();
                previousLastName = previous.LastName.ToLower();
                newSession.Close();
                newSession.Dispose();
            }
            string newFirstNameInitial = user.FirstName.Substring(0, 1).ToLower();
            string newLastName = user.LastName.ToLower();
            // Has either the first name or last name changed?
            if (previousFirstNameInitial != newFirstNameInitial ||
                previousLastName != newLastName)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Gets a username based on your first name/last name. Note that
        /// the username is converted to be in lowercase.
        /// </summary>
        /// <param name="data">Entity instance to evaluate.</param>
        /// <returns>Username.</returns>
        private string GetNewUserName(ISession session, User user)
        {
            string userName = user.FirstName.Substring(0, 1) + user.LastName;
            // Check to see if username has been used. If so, add an initial number
            // to the end.
            List<User> users = User.GetUsersBySmiliarUsername(session, userName);
            if (users.Count > 0)
            {
                userName = String.Format("{0}{1}", userName, users.Count);
            }
            return userName.ToLower();
        }

        public override void Implement(ISession session, EntityBase entity)
        {
            if (entity.GetOperation() == EntityBase.Operations.Save)
            {
                User user = (User)entity;
                if (user.Id == 0)
                {
                    user.Username = GetNewUserName(session, user);
                }
                else
                {
                    // Has either the first name or last name changed?
                    if (IsChanged(session, user))
                    {
                        if (user.LastLogin != null)
                        {
                            if (user.LastLogout == null)
                            {
                                if (user.LastLogin < DateTime.Now)
                                {
                                    // This is the first time that the user has logged in.
                                    // User has logged in but has not logged out yet.
                                    throw new Exceptions.BusinessRuleViolation(String.Format(
                                        "{0} is currently logged in. Unable to remove user at this time.", user.Username));
                                }
                            }
                            else
                            {
                                if (user.LastLogin < user.LastLogin)
                                {
                                    // This is NOT the first time that the user has logged in.
                                    // User has logged in but has not logged out yet.
                                    throw new Exceptions.BusinessRuleViolation(String.Format(
                                        "{0} is currently logged in. Unable to remove user at this time.", user.Username));
                                }
                            }
                        }
                        user.Username = GetNewUserName(session, user);
                    }
                }
            }
        }

        public override bool QueryBooleanProperty(string propertyName)
        {
            switch (propertyName)
            {
                case "IsEnableUserNameTextBox":
                    return false;
            }
            throw new MissingPropertyName(String.Format("Property name is missing: {0}", propertyName));
        }
    }
}
